package transactions;

import java.util.Iterator;
import java.util.concurrent.BlockingQueue;

import util.configuration.ConfigLoader;

public abstract class AbstractTransactionManager {
	
	private TransactionManagerScheduler monitor;
	private TransactionManagerCommunicator communicator;
	private TransactionManagerTimeoutManager timeOutManager;
	private IStableStorage log;
	protected BlockingQueue<AbstractTransaction> transactions;
	protected BlockingQueue<IResourceManager> rm;
	protected static long lastTransactionID;
	
	public AbstractTransactionManager()
	{
		this.monitor = new TransactionManagerScheduler(this);
		this.timeOutManager = new TransactionManagerTimeoutManager(this);
	}
	
	public long addTransaction(AbstractTransaction transaction)
	{	
		if (lastTransactionID == Long.MAX_VALUE )  lastTransactionID = 0; else lastTransactionID++;
		transaction.setID(lastTransactionID);
		startTimeout(transaction, transaction.getTimeout());
		return lastTransactionID;
	}
	
	
	public void removeTransaction(long id)
	{
		for (Iterator<AbstractTransaction> iterator = transactions.iterator(); iterator.hasNext();) {
			AbstractTransaction trans = (AbstractTransaction) iterator.next();
			if (trans.getID() == id ) transactions.remove(trans);
		}
	}
	
	public void removeTransaction(AbstractTransaction transaction)
	{
		transactions.remove(transaction);
	}
	/*public void schedule(ITransaction transaction)
	{
		if (transactions.isEmpty())
			transactions.wait()
			else tr
	}*/
	
	
	
	public boolean executeTransaction(AbstractTransaction transaction)
	{
		//timeOutManager.monitor(transaction, ConfigLoader.TransactionTimeout);
		for( int i = 0 ; i< ConfigLoader.TransactionNRetrive; i++)
		{
			try
			{
				prepare(transaction);
				// TODO: apdaos
			}
			catch(Exception e)
			{
				
			}
		}
		return true;
	}
	
	private void startTimeout(AbstractTransaction transaction, long timeout)
	{
		this.timeOutManager.monitor(transaction, timeout);		
	}
	
	private void stopTimeout(AbstractTransaction transaction)
	{
		this.timeOutManager.clearTimeout(transaction);
	}
	
	public abstract boolean prepare(AbstractTransaction transaction);
	public abstract boolean commit(AbstractTransaction transaction);
	public abstract boolean abort(AbstractTransaction transaction, TransactionAbortReason reason);
	public BlockingQueue<AbstractTransaction> getTransactions(){return transactions;}

	private boolean log(AbstractTransaction transaction, String message)
	{
		return true;
	}
	
}
